package com.java110.api.websocket;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.java110.core.client.RestTemplate;
import com.java110.core.factory.RestTemplateFactory;
import com.java110.dto.WsDataDto;
import com.java110.dto.machine.MachineDto;
import com.java110.utils.cache.CommonCache;
import com.java110.utils.constant.MallConstant;
import com.java110.utils.factory.ApplicationContextFactory;
import com.java110.utils.util.StringUtil;
import com.java110.vo.ResultVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName 视频 ws
 * @Description TODO
 * @Author wuxw
 * @Date 2020/5/25 12:13
 * @Version 1.0
 * add by wuxw 2020/5/25
 **/
@ServerEndpoint("/ws/parkingArea/{clientId}")
@Component
public class ParkingAreaWebsocket {

    private static Logger logger = LoggerFactory.getLogger( ParkingAreaWebsocket.class );

    /**
     * 静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    private static int onlineCount = 0;
    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
     */
    private static ConcurrentHashMap<String, ParkingAreaWebsocket> webSocketMap = new ConcurrentHashMap<>();
    private static ConcurrentHashMap<String, List<MachineDto>> machineMap = new ConcurrentHashMap<>();

    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
     */
    private static ConcurrentHashMap<String, String> clientMachineMap = new ConcurrentHashMap<>();
    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private RestTemplate outRestTemplate;

    private Session session;
    /**
     * 接收clientId
     */
    private String clientId = "";


    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("clientId") String clientId) {

        this.clientId = clientId;
        //获取rest对象
        StringHttpMessageConverter m = new StringHttpMessageConverter( Charset.forName( "UTF-8" ) );
        outRestTemplate = new RestTemplateBuilder().additionalMessageConverters( m ).build( RestTemplate.class );

        //加入set中
        addOnlineCount();
        //在线数加1
        logger.debug( "用户连接:" + clientId + ",当前在线人数为:" + getOnlineCount() );

//        try {
//            sendMessage( "连接成功" );
//        } catch (IOException e) {
//            logger.error( "用户:" + clientId + ",网络异常!!!!!!" );
//        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if (machineMap.containsKey( clientId )) {
            List<MachineDto> tmpMachineDto = machineMap.get( clientId );
            for (MachineDto machineDto : tmpMachineDto) {
                //加入set中
                JSONArray clients = JSONObject.parseArray( CommonCache.getValue( machineDto.getMachineId() ) );
                if (clients == null || clients.size() < 1) {
                    JSONObject reqJsonBye = new JSONObject();
                    reqJsonBye.put( "action", MachineDto.SIP_BYE );
                    reqJsonBye.put( "id", machineDto.getMachineCode() );
                    ResponseEntity<String> responseByeEntity = RestTemplateFactory.restOutSipTemplate( reqJsonBye, outRestTemplate, MallConstant.SIP_ACTION, HttpMethod.GET );
                    if (responseByeEntity != null) {
                        if (responseByeEntity.getStatusCode() != HttpStatus.OK) {
                            throw new IllegalArgumentException( responseByeEntity.getBody() );
                        }
                    }
                } else {
                    for (int clientsIndex = 0; clientsIndex < clients.size(); clientsIndex++) {
                        String value = clientId + machineDto.getMachineCode() + machineDto.getMachineVersion();
                        if (value.equals( clients.getString( clientsIndex ) )) {
                            clients.remove( clientsIndex );
                        }
                    }
                    CommonCache.setValue( machineDto.getMachineId(), clients.toJSONString() );
                }
            }
            for (MachineDto machineDto : tmpMachineDto) {
                //加入set中
                JSONArray clients = JSONObject.parseArray( CommonCache.getValue( machineDto.getMachineId() ) );
                if (clients == null || clients.size() < 1) {
                    JSONObject reqJsonBye = new JSONObject();
                    reqJsonBye.put( "action", MachineDto.SIP_BYE );
                    reqJsonBye.put( "id", machineDto.getMachineCode() );
                    reqJsonBye.put( "chid", machineDto.getMachineVersion());
                    ResponseEntity<String> responseByeEntity = RestTemplateFactory.restOutSipTemplate( reqJsonBye, outRestTemplate, MallConstant.SIP_ACTION, HttpMethod.GET );
                    if (responseByeEntity != null) {
                        if (responseByeEntity.getStatusCode() != HttpStatus.OK) {
                            throw new IllegalArgumentException( responseByeEntity.getBody() );
                        }
                    }
                }
            }
            //从set中删除
            subOnlineCount();
        }
        logger.info( "用户退出:" + clientId + ",当前在线人数为:" + getOnlineCount() );
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) throws Exception {
        logger.info( "用户消息:" + clientId + ",客户端：" + clientId + ",报文:" + message );
        //可以群发消息
        //消息保存到数据库、redis
        if (StringUtil.isEmpty( message )) {
            ResultVo resultVo = new ResultVo( ResultVo.CODE_ERROR, "未包含内容" );
            return;
        }

        if (StringUtil.isJsonArray( message )) {
            List<MachineDto> wsMachineDto = JSONArray.parseArray( message, MachineDto.class );
            if (machineMap.containsKey( clientId )) {
                List<MachineDto> tmpMachineDto = machineMap.get( clientId );
                for (MachineDto machine : wsMachineDto) {
                    tmpMachineDto.add( machine );
                }
                machineMap.remove( clientId );
                machineMap.put( clientId, tmpMachineDto );
            } else {
                machineMap.put( clientId, wsMachineDto );
            }
            return;
        }
    }

    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        logger.error( "用户错误:" + this.clientId + ",原因:" + error.getMessage() );
        error.printStackTrace();
    }

    /**
     * 实现服务器主动推送
     */
//    public void sendMessage(String message) throws IOException {
//        this.session.getBasicRemote().sendText( message );
//    }


    /**
     * 发送设备监控信息
     */
    public static void sendInfo(String message, String boxId) throws IOException {
        logger.info( "发送消息到:" + boxId + "，报文:" + message );
        for (ParkingAreaWebsocket server : webSocketMap.values()) {
            if (boxId.equals( server.clientId )) {
                webSocketMap.get( server.clientId );
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        ParkingAreaWebsocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        ParkingAreaWebsocket.onlineCount--;
    }
}
